/*
 * SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
 *
 * SPDX-License-Identifier: MulanPSL-2.0
 */
#![allow(
    dead_code,
    unreachable_code,
    unused_variables,
    mutable_transmutes,
    non_camel_case_types,
    non_snake_case,
    non_upper_case_globals,
    unused_assignments,
    unused_mut,
    clippy::never_loop
)]

use crate::common::*;
use crate::sudoers::sudo_user;

extern "C" {
    static mut sudoers_subsystem_ids: [libc::c_uint; 0];
    fn strlen(_: *const libc::c_char) -> libc::c_ulong;
    fn malloc(_: libc::c_ulong) -> *mut libc::c_void;
    fn sudo_warnx_nodebug_v1(fmt: *const libc::c_char, _: ...);
    fn sudo_debug_printf2_v1(
        func: *const libc::c_char,
        file: *const libc::c_char,
        line: libc::c_int,
        level: libc::c_int,
        fmt: *const libc::c_char,
        _: ...
    );
    fn sudo_strlcpy(dst: *mut libc::c_char, src: *const libc::c_char, siz: size_t) -> size_t;
    fn memcpy(_: *mut libc::c_void, _: *const libc::c_void, _: libc::c_ulong) -> *mut libc::c_void;
}

#[no_mangle]
pub fn expand_prompt(
    mut old_prompt: *const libc::c_char,
    mut auth_user: *const libc::c_char,
) -> *mut libc::c_char {
    let mut len: size_t = 0;
    let mut n: size_t = 0;
    let mut subst: libc::c_int = 0;
    let mut p: *const libc::c_char = std::ptr::null_mut::<libc::c_char>();
    let mut np: *mut libc::c_char = std::ptr::null_mut::<libc::c_char>();
    let mut new_prompt: *mut libc::c_char = std::ptr::null_mut::<libc::c_char>();
    let mut endp: *mut libc::c_char = std::ptr::null_mut::<libc::c_char>();
    unsafe {
        debug_decl!(SUDOERS_DEBUG_AUTH!());

        subst = 0 as libc::c_int;
        p = old_prompt;
        len = strlen(old_prompt);
        while *p != 0 {
            if *p.offset(0 as libc::c_int as isize) as libc::c_int == '%' as i32 {
                match *p.offset(1 as libc::c_int as isize) as u8 as char {
                    'h' => {
                        p = p.offset(1);
                        len = (len as libc::c_ulong).wrapping_add(
                            (strlen(sudo_user.shost))
                                .wrapping_sub(2 as libc::c_int as libc::c_ulong),
                        ) as size_t as size_t;
                        subst = 1 as libc::c_int;
                    }

                    'H' => {
                        p = p.offset(1);
                        len = (len as libc::c_ulong).wrapping_add(
                            (strlen(sudo_user.host))
                                .wrapping_sub(2 as libc::c_int as libc::c_ulong),
                        ) as size_t as size_t;
                        subst = 1 as libc::c_int;
                    }

                    'p' => {
                        p = p.offset(1);
                        len = (len as libc::c_ulong).wrapping_add(
                            (strlen(auth_user)).wrapping_sub(2 as libc::c_int as libc::c_ulong),
                        ) as size_t as size_t;
                        subst = 1 as libc::c_int;
                    }

                    'u' => {
                        p = p.offset(1);
                        len = (len as libc::c_ulong).wrapping_add(
                            (strlen(sudo_user.name))
                                .wrapping_sub(2 as libc::c_int as libc::c_ulong),
                        ) as size_t as size_t;
                        subst = 1 as libc::c_int;
                    }

                    'U' => {
                        p = p.offset(1);
                        len = (len as libc::c_ulong).wrapping_add(
                            (strlen((*sudo_user._runas_pw).pw_name))
                                .wrapping_sub(2 as libc::c_int as libc::c_ulong),
                        ) as size_t as size_t;
                        subst = 1 as libc::c_int;
                    }
                    '%' => {
                        p = p.offset(1);
                        len = len.wrapping_sub(1);
                        subst = 1 as libc::c_int;
                    }

                    _ => {}
                } //end of match
            } //end of if
            p = p.offset(1);
        } //end of while

        len = len.wrapping_add(1);
        new_prompt = malloc(len) as *mut libc::c_char;
        if new_prompt.is_null() {
            sudo_warnx!(
                b"%s: %s\0" as *const u8 as *const libc::c_char,
                get_function_name!(),
                b"unable to allocate memory\0" as *const u8 as *const libc::c_char
            );
            debug_return_str!(std::ptr::null_mut::<libc::c_char>());
        }

        'oflow: loop {
            if subst != 0 {
                endp = new_prompt.offset(len as isize);
                p = old_prompt;
                np = new_prompt;
                loop {
                    if *p == 0 {
                        break;
                    }
                    if *p.offset(0 as libc::c_int as isize) as libc::c_int == '%' as i32 {
                        match *p.offset(1 as libc::c_int as isize) as u8 as char {
                            'h' => {
                                p = p.offset(1);
                                n = sudo_strlcpy(
                                    np,
                                    sudo_user.shost,
                                    np.offset_from(endp) as libc::c_long as size_t,
                                );
                                if n >= np.offset_from(endp) as libc::c_long as size_t {
                                    break 'oflow;
                                }
                                np = np.offset(n as isize);
                                p = p.offset(1);
                                continue;
                            }
                            'H' => {
                                p = p.offset(1);
                                n = sudo_strlcpy(
                                    np,
                                    sudo_user.host,
                                    np.offset_from(endp) as libc::c_long as size_t,
                                );
                                if n >= np.offset_from(endp) as libc::c_long as size_t {
                                    break 'oflow;
                                }
                                np = np.offset(n as isize);
                                p = p.offset(1);
                                continue;
                            }
                            'p' => {
                                p = p.offset(1);
                                n = sudo_strlcpy(
                                    np,
                                    auth_user,
                                    np.offset_from(endp) as libc::c_long as size_t,
                                );
                                if n >= np.offset_from(endp) as libc::c_long as size_t {
                                    break 'oflow;
                                }
                                np = np.offset(n as isize);
                                p = p.offset(1);
                                continue;
                            }
                            'u' => {
                                p = p.offset(1);
                                n = sudo_strlcpy(
                                    np,
                                    sudo_user.name,
                                    np.offset_from(endp) as libc::c_long as size_t,
                                );
                                if n >= np.offset_from(endp) as libc::c_long as size_t {
                                    break 'oflow;
                                }
                                np = np.offset(n as isize);
                                p = p.offset(1);
                                continue;
                            }
                            'U' => {
                                p = p.offset(1);
                                n = sudo_strlcpy(
                                    np,
                                    (*sudo_user._runas_pw).pw_name,
                                    np.offset_from(endp) as libc::c_long as size_t,
                                );
                                if n >= np.offset_from(endp) as libc::c_long as size_t {
                                    break 'oflow;
                                }
                                np = np.offset(n as isize);
                                p = p.offset(1);
                                continue;
                            }
                            '%' => {
                                p = p.offset(1);
                            }
                            _ => {}
                        }
                    }
                    *np = *p;
                    np = np.offset(1);
                    if np >= endp {
                        break 'oflow;
                    }
                    p = p.offset(1);
                }
                *np = '\u{0}' as i32 as libc::c_char;
            } else {
                memcpy(
                    new_prompt as *mut libc::c_void,
                    old_prompt as *const libc::c_void,
                    len,
                );
            }

            debug_return_str!(new_prompt as *mut libc::c_char);

            break 'oflow;
        } //end of oflow;
        free(new_prompt as *mut libc::c_void);
        sudo_warnx!(
            b"internal error, %s overflow\0" as *const u8 as *const libc::c_char,
            get_function_name!(),
        );
        debug_return_str!(std::ptr::null_mut::<libc::c_char>());
    } //unsafe
}
